package org.mog.music.service.impl;

import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mog.api.feignClients.AlbumClient;
import context.BaseContext;
import context.MQContext;
import context.MusicInfoContext;
import context.UserContext;
import dto.MusicInsertDTO;
import dto.MusicPageDTO;
import dto.MusicSearchDTO;
import entity.pojo.Album;
import entity.pojo.Music;
import entity.resullt.PageResult;
import entity.resullt.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.mog.file.config.MinIOConfigProperties;
import org.mog.file.service.FileStorageService;
import org.mog.music.mapper.MusicMapper;
import org.mog.music.service.IMusicService;
import org.mog.music.service.IUserMusicService;
import org.mog.music.thread.UpdateAndInsertThread;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import vo.MusicPageVO;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

@Service
@RequiredArgsConstructor
@Slf4j
public class MusicService implements IMusicService {
    private final MinIOConfigProperties minIOConfigProperties;
    private final MusicMapper musicMapper;
    private final IUserMusicService userMusicService;
    private final RestTemplate restTemplate;
    private final AlbumClient albumClient;
    private final RabbitTemplate rabbitTemplate;
    private final FileStorageService fileStorageService;

    /**
     * 获取音乐分页数据
     *
     * @param musicPageDTO
     * @return
     */
    @Override
    public PageResult<MusicPageVO> getMusicPage(MusicPageDTO musicPageDTO) {
        List<Long> musicIds = new ArrayList<>();
        if (musicPageDTO.getMyself() != null && musicPageDTO.getMyself() == 1) {
            // 用户id自动填充
            musicIds = musicMapper.getMusicIdByUserId(UserContext.getId());
        }

        //设置分页条件
        PageHelper.startPage(musicPageDTO.getPage(), musicPageDTO.getPageSize(), true);

        //执行查询
        List<Music> musicList;
        if (musicPageDTO.getMyself() != null && musicPageDTO.getMyself() == 1) {
            musicList = musicMapper.getMusicListByIds(musicIds);
        } else {
            musicList = musicMapper.getShareMusicList(musicPageDTO);
        }

        Page<Music> musicPage = (Page<Music>) musicList;

        List<MusicPageVO> musicPageVOList = new ArrayList<>();
        for (Music music : musicList) {
            MusicPageVO musicPageVO = new MusicPageVO();
            BeanUtils.copyProperties(music, musicPageVO);
            musicPageVO.setAudio(musicPageVO.getAudio().replaceAll("[\\r|\\n]", ""));
            musicPageVOList.add(musicPageVO);
        }

        return new PageResult<>(musicPage.getTotal(), musicPageVOList);
    }

    /**
     * 新增音乐
     *
     * @param musicInsertDTO
     */
    @Override
    public void insertMusic(MusicInsertDTO musicInsertDTO, HttpServletRequest request, Long userId) {
        //查询专辑是否已有
        String albumId = PinyinUtil.getFirstLetter(
                        musicInsertDTO.getAlbumName() + musicInsertDTO.getSinger(), "")
                .toUpperCase().replaceAll(" ", "") + Base64Encoder.encode(musicInsertDTO.getAlbumName());
        Result<Album> albumRes = albumClient.getById(albumId);
        if (albumRes.getData() == null) {
            Album album = Album.builder()
                    .id(albumId)
                    .name(musicInsertDTO.getAlbumName())
                    .cover(musicInsertDTO.getAlbumCover())
                    .build();

            //通过MQ发送消息，新增专辑
            try {
                rabbitTemplate.convertAndSend(
                        MQContext.ALBUM_EXCHANGE,
                        MQContext.NEW_ALBUM_ROUTING_KEY,
                        JSONUtil.toJsonStr(album));
            } catch (AmqpException e) {
                log.error("发送新增专辑消息失败：专辑名：{}；id：{}", musicInsertDTO.getAlbumName(), album);
            }
        }
        musicInsertDTO.setAlbumId(albumId);
        //判断音乐是否已有
        long musicId = 0;
        if (albumRes.getData() == null) {
            //不存在
            musicMapper.insertMusic(musicInsertDTO);
            musicId = musicInsertDTO.getId();
        } else {
            Music music = musicMapper.getMusicByInfo(
                    musicInsertDTO.getName(),
                    musicInsertDTO.getSinger(),
                    musicInsertDTO.getAlbumName());
            log.info("music：{}", music);
            if (music == null) {
                //不存在
                musicMapper.insertMusic(musicInsertDTO);
                musicId = musicInsertDTO.getId();
            } else {
                musicId = music.getId();
            }
        }

        //新增音乐用户记录
        userMusicService.insert(request == null ?
                (userId) :
                (Long.valueOf(request.getHeader("user-info"))), musicId);
    }

    /**
     * 搜索音乐
     *
     * @param musicSearchDTO
     * @return
     */
    @Override
    public PageResult<MusicPageVO> searchMusic(MusicSearchDTO musicSearchDTO) {
        /*//清空ThreadLocal
        SearchWordContext.clear();
        //设置ThreadLocal
        SearchWordContext.setWord(musicSearchDTO.getKeyword());*/

        String url = BaseContext.spliceSearchUrlWithArgs(
                musicSearchDTO.getKeyword(),
                musicSearchDTO.getPage(),
                "json"
        );

        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        String json = responseEntity.getBody();

        //解析json数据
        int total = (int) JSONUtil.getByPath(JSONUtil.toBean(json, JSON.class), "data.total");
        JSONArray infoJsonArr = (JSONArray) JSONUtil.getByPath(JSONUtil.toBean(json, JSON.class), "data.info");

        //封装进VO对象
        List<MusicPageVO> musicPageVOList = new ArrayList<>();
        for (Object ele : infoJsonArr) {
            JSON eleJson = JSONUtil.parse(ele);
            musicPageVOList.add(
                    MusicPageVO.builder()
                            .name((String) JSONUtil.getByPath(eleJson, "songname"))
                            .singer((String) JSONUtil.getByPath(eleJson, "singername"))
                            .albumName((String) JSONUtil.getByPath(eleJson, "album_name"))
                            .albumCover(((String) JSONUtil.getByPath(
                                    eleJson,
                                    "trans_param.union_cover"))
                                    .replaceAll("\\{size}", "720"))
                            .build()

            );
        }

        return new PageResult<>(total, musicPageVOList);
    }

    /**
     * 服务器内分页搜索音乐
     *
     * @param musicSearchDTO
     * @return
     */
    @Override
    public PageResult<MusicPageVO> localSearch(MusicSearchDTO musicSearchDTO) {
        musicMapper.searchByKeyword(musicSearchDTO);


        return null;
    }

    /**
     * 下载或播放音乐
     *
     * @param page
     * @param pageSize
     * @param n
     * @return
     */
    @Override
    public String playOrDownloadMusic(
            Integer page, Integer pageSize, String keyword, Integer n, HttpServletRequest request) throws Exception {
        String url = BaseContext.spliceGetMusicUrlWithArgs(
                keyword,
                ((page - 1) * pageSize) + n,
                page * pageSize,
                "json",
                128);

        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        String str = responseEntity.getBody();
        JSON json = JSONUtil.toBean(str, JSON.class);
        String musicUrl = (String) json.getByPath("music_url");
        String singer = (String) json.getByPath("singer");

        System.out.println("请求结果：" + str);

        //解析json数据，新增音乐
        //获取专辑信息
        PageResult<MusicPageVO> res = this.searchMusic(MusicSearchDTO.builder()
                .keyword(keyword)
                .page(page)
                .pageSize(pageSize)
                .build());
        MusicPageVO item = res.getRecords().get(n - 1);


        String musicName = (String) json.getByPath("title");
        MusicInsertDTO musicInsertDTO = MusicInsertDTO.builder()
                .name(musicName)
                .singer(singer)
                .albumName(item.getAlbumName())
                .albumCover(item.getAlbumCover())
                .audio(musicUrl)
                .build();

        //上传音乐、新增音乐
        Long userId = Long.valueOf(request.getHeader("user-info"));
        log.info("userId={}", userId);
        UserContext.setId(userId);

        //开启线程，上传并添加
        updateAndInsert(musicInsertDTO, userId);

        return musicUrl.split("\\.mp3")[0] + ".mp3";
    }

    /**
     * 上传音乐文件到文件系统(minio)
     *
     * @return
     */
    @Override
    public String upload2FS(MusicInsertDTO dto) throws Exception {
        log.info("准备上传文件：{}", dto.getSinger() + "-" + dto.getName() + ".mp3");

        String singer = dto.getSinger();
        String albumName = dto.getAlbumName();
        String name = dto.getName();
        String audioUrl = dto.getAudio();
        //判断文件是否已经存在
        String filePath = ((StringUtils.isBlank(singer) ? MusicInfoContext.OTHER : singer)
                + "/"
                + (StringUtils.isBlank(albumName) ? MusicInfoContext.OTHER : albumName))
                + (singer + "-" + name + ".mp3").replaceAll(" ", "");
        boolean exist = fileStorageService.isExist(
                minIOConfigProperties.getBucket(),
                filePath);

        log.info("查询路径{}是否存在", filePath);

        //存在
        if (exist) {
            String url = minIOConfigProperties.getReadPath() + "/"
                    + minIOConfigProperties.getBucket() + "/"
                    + filePath;
            log.info("文件已存在：{}", url);
            return url;
        }

        //不存在
        InputStream is = new URL(audioUrl).openStream();

        String newUrl = fileStorageService.uploadAudioFile(
                ((StringUtils.isBlank(singer) ? MusicInfoContext.OTHER : singer) + "/"
                        + (StringUtils.isBlank(albumName) ? MusicInfoContext.OTHER : albumName)),
                (singer + "-" + name + ".mp3").replaceAll(" ", ""),
                is
        );
        log.info("上传文件成功：{}", newUrl);

        return newUrl;
    }

    /**
     * 增加播放次数
     *
     * @param id
     */
    @Override
    public Result addPlays(Long id) {
        if (id == null) {
            return Result.error("参数错误");
        }

        musicMapper.addPlays(id);
        return Result.success();
    }


    /**
     * 上传并添加
     *
     * @param dto
     * @param userId
     */
    public void updateAndInsert(MusicInsertDTO dto, Long userId) {
        UpdateAndInsertThread thread = UpdateAndInsertThread.builder()
                .musicInsertDTO(dto)
                .musicService(this)
                .request(null)
                .userId(userId)
                .build();
        thread.start();
    }


}
